#pragma once
#include "../common/net.hpp"
//将注册了的方法进行管理的文件
namespace BRpc
{
    namespace Server
    {
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT,
        };
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamsDescribe = std::pair<std::string, VType>;

        public:
            ServiceDescribe(const std::string &&mname, const std::vector<ParamsDescribe> &&paramD, const ServiceCallback &&callback,
                            VType &&returnType)
            {
                _method_name = std::move(mname);
                _params_desc = std::move(paramD);
                _callback = std::move(callback);
                _return_type = std::move(returnType);
            }
            std::string &method()
            {
                return _method_name;
            }
            // 检测所需参数是否都有了
            bool paramCheck(const Json::Value &params)
            {
                ELOG("检验参数");
                for (auto &param : _params_desc)
                {
                    if (params.isMember(param.first) == false)
                    {
                        ELOG("参数名称不匹配,缺失字段%s", param.first.c_str());
                        return false;
                    }
                    if (check(param.second, params[param.first]) == false)
                    {
                        ELOG("%s 参数类型校验失败！", param.first.c_str());
                        return false;
                    }
                }
                ELOG("参数正确");
                return true;
            }
            // 调用业务处理方法
            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if (rtypeCheck(result) == false)
                {
                    ELOG("回调函数返回值不对");
                    return false;
                }
                return true;
            }

        private:
            // 检测返回值是否一致
            bool rtypeCheck(const Json::Value &val)
            {
                return check(_return_type, val);
            }
            // 检测类型是否与所需类型一致
            bool check(VType vtype, const Json::Value &val)
            {
                switch (vtype)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        private:
            std::string _method_name;                 // 方法名称
            ServiceCallback _callback;                // 方法
            std::vector<ParamsDescribe> _params_desc; // 方法所需参数描述
            VType _return_type;                       // 返回类型
        };
        // 工厂加建造者模式
        class SDescribeFactory
        {
        public:
            void setMethodName(const std::string &name)
            {
                _method_name = name;
            }
            void setReturnType(VType type)
            {
                _return_type = type;
            }
            void setParamsDesc(const std::string &pname, VType vtype)
            {
                _params_desc.push_back(ServiceDescribe::ParamsDescribe(pname, vtype));
            }
            void setCallback(const ServiceDescribe::ServiceCallback &cb)
            {
                _callback = cb;
            }
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_params_desc),
                                                         std::move(_callback), std::move(_return_type));
            }

        private:
            std::string _method_name;
            ServiceDescribe::ServiceCallback _callback;
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc;
            VType _return_type;
        };
        // 管理服务的类
        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;

        public:
            void insert(const ServiceDescribe::ptr service)
            {
                // 检测方法是否已经存在了
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = manager.find(service->method());
                if (it == manager.end())
                {
                    manager.insert(std::make_pair(service->method(), service));
                }
            }
            ServiceDescribe::ptr select(const std::string method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = manager.find(method);
                if (it == manager.end())
                {
                    ELOG("此服务器未提供%s服务", method);
                    return ServiceDescribe::ptr();
                }
                return it->second;
            }
            void remove(const std::string method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = manager.find(method);
                if (it != manager.end())
                {
                    manager.erase(method);
                }
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> manager;
        };
        //
        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;

        public:
            RpcRouter() : _manager(std::make_shared<ServiceManager>()) {}
            // 收到请求后的操作
            void onRequest(const BaseConnection::ptr &conn, const RpcRequest::ptr &request)
            {
                auto service = _manager->select(request->method());
                // 查询服务器是否提供了方法
                if (service == nullptr)
                {
                    ELOG("不存在方法%s", request->method());
                    return response(conn, request, Json::Value(), BRpc::RCode::RCODE_NOT_FOUND_SERVICE);
                }
                // 进行参数校验，确定能否提供服务
                if (service->paramCheck(request->parameters()) == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                // 调用回调函数处理业务
                Json::Value result;
                auto ret = service->call(request->parameters(), result);
                if (ret == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                // 将处理结果发送
                return response(conn, request, result, BRpc::RCode::RCODE_OK);
            }
            // 注册方法
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                return _manager->insert(service);
            }

        private:
            // 构建应答并发送
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &request, const Json::Value &result, BRpc::RCode rcode)
            {
                auto msg = BRpc::MessageFactory::create<RpcResponse>();
                // id要设置成请求id 让客户端来分辨这条回应是回应哪个请求的
                msg->setId(request->id());
                msg->setMType(BRpc::MType::RSP_RPC);
                msg->setResult(result);
                msg->setRCode(rcode);
                conn->send(msg);
                ELOG("发送RPC响应，ID=%s, 结果=%s", msg->id().c_str(), msg->result().toStyledString().c_str());
            }

        private:
            ServiceManager::ptr _manager;
        };
    }
}